#include "DbConnectionPool.h"
#include <any>
#include <cfloat>
#include <chrono>
#include <cppconn/connection.h>
#include <cppconn/exception.h>
#include <cppconn/mysql_driver.h>
#include <memory>
#include <mutex>
#include <queue>
#include <stdexcept>
#include <sys/socket.h>
#include <system_error>
#include <cppconn/statement.h>
#include <cppconn/resultset.h>
#include <thread>
#include "Mylogger.h"
#include "Configuration.h"
#include <map>
#include <string>
#include <stdlib.h>
using std::string;

namespace SOS{


DbConnectionPool::DbConnectionPool(){
    printf("28\n");
    loadConfig();
    for (int i = 0; i < _initSize; ++i) {
        sql::Connection* conn = createNewConnection();
        _idleConns.push({conn, std::chrono::system_clock::now()});
    }
    _stopRecycling = false;
    _recycleThread = std::thread(&DbConnectionPool::recycleIdleConnections, this);
}

DbConnectionPool::~DbConnectionPool(){
     _stopRecycling = true;          // 通知回收线程退出
    if (_recycleThread.joinable()) {
        _recycleThread.join();      // 等待线程结束
    }

    // 释放所有连接
    while (!_idleConns.empty()) {
        delete _idleConns.front()._conn;
        _idleConns.pop();
    }
    for (auto* conn : _activeConns) {
        delete conn;
    }
}

//单例初始化
DbConnectionPool & DbConnectionPool::getInstance(){
   static DbConnectionPool pInstance;
   return pInstance;
}

sql::Connection* DbConnectionPool::getConnection(int timeoutMs){
    std::unique_lock<std::mutex> lock(_mutex);
    //空闲连接与活跃连接没有超过上限
    if(_idleConns.empty() && (_activeConns.size() + _idleConns.size() < _maxSize)){
        //创建新连接
        sql::Connection *newConn = createNewConnection();
        //新连接有效，加入活跃连接集合
        if(newConn){
            _activeConns.insert(newConn);
            return newConn;
        }
    }
    //在timeoutMs的时间计数内等待可用连接，获取连接
    if(_cond.wait_for(lock,std::chrono::milliseconds(timeoutMs),
       [this]{return !_idleConns.empty();})){
            ConnectionMeta meta = _idleConns.front();
            _idleConns.pop();
            
            //进行健康检查
            if(!validateConnection(meta._conn)){
                delete meta._conn;
                sql::Connection* newConn = createNewConnection();
                _activeConns.insert(newConn);
                return newConn;
            }
        _activeConns.insert(meta._conn);
        return meta._conn;
    }
    
    throw std::runtime_error("Connection wait timeout\n");
}




void DbConnectionPool::releaseConnection(sql::Connection* conn){
    std::unique_lock<std::mutex> lock(_mutex);
    auto it = _activeConns.find(conn);
    if(it != _activeConns.end()){
        _activeConns.erase(conn);
    }
    
    //检查连接有效性
    if(validateConnection(conn)){
        //连接有效就放入队列
        _idleConns.push({conn,std::chrono::system_clock::now()});
       _cond.notify_one();
    }else{
        //无效直接销毁
        delete conn;
    }
    //防止重复归还

}


sql::Connection* DbConnectionPool::createNewConnection(){
    try{
        //获取mysql驱动实例
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
        this->loadConfig();
        sql::ConnectOptionsMap connection_properties;
        connection_properties["hostName"] = _url;
        connection_properties["userName"] = _user;
        connection_properties["password"] = _passwd;

        //添加高级连接选项
        connection_properties["OPT_RECONNECT"] = true; //启用自动重连
        connection_properties["OPT_CONNECT_TIMEOUT"] = 5; //连接超时时限(s)
        connection_properties["OPT_CHARSET_NAME"] = "utf8mb4";//设置通用字符集
                                                              
        return driver->connect(connection_properties);
    }catch (const sql::SQLException& e){
        //异常处理
        LOGDEBUG("创建连接失败：ERROR",e.getErrorCode(),"<<",e.getSQLState(),"<<",e.what());
        return nullptr;
    }catch (const std::runtime_error &e){
        //驱动加载失败处理
        LOGDEBUG("加载驱动失败：",e.what());
        return nullptr;
    }    
}


bool DbConnectionPool::validateConnection(sql::Connection* conn){
    try{
        std::unique_ptr<sql::Statement> stmt(conn->createStatement());
        std::unique_ptr<sql::ResultSet> res(stmt -> executeQuery("select 1"));
        return res->next() && res->getInt(1) ==  1;
    } catch(sql::SQLException&){
        return false;
    }
}

//空闲连接回收线程
void DbConnectionPool::recycleIdleConnections(){
    while(!_stopRecycling){
        //数据库连接循环还未结束
        std::this_thread::sleep_for(std::chrono::seconds(10));
        
        std::unique_lock<std::mutex> lock(_mutex);
        auto now = std::chrono::system_clock::now();
        size_t initialIdleCnt = _idleConns.size();
        
        //重建队列，过滤超时连接
        std::queue<ConnectionMeta> validque;
        //空闲连接队列不空就循环
        while(!validque.empty()){
            ConnectionMeta meta = _idleConns.front();
            _idleConns.pop();

            auto idleSeconds = std::chrono::duration_cast<std::chrono::seconds>(now - meta._lastused).count();
            
            if(idleSeconds < _maxIdleTimesSec){
                validque.push(meta);
            }else{
                delete meta._conn;
            }
        }
        _idleConns = std::move(validque);
    }
}

void DbConnectionPool::loadConfig(){
    std::map conf_map = Configuration::getConfigurationInstance()->getConfigInfo();
    _url = conf_map["dburl"];
    _user = conf_map["user"];
    _passwd = conf_map["passwd"];
    _initSize = stoi(conf_map["DbConnectionPoolInitsize"]);
    _maxSize = stoi(conf_map["DbConnectionPoolMaxSize"]);
    _maxIdleTimesSec = stoi(conf_map["DbConnectionPoolMaxIdleTimeSec"]);
}




}// end of namespace SOS;
